<?php
/**
 * jishupu-cms
 * @Author:技术铺
 * @Date:2021/11/22
 */

namespace App\Services;

use App\Http\Resources\MenuCollection;
use App\Models\InfoCategory;
use App\Models\Menu;
use App\Models\MenuPermission;
use App\Models\User;
use App\Models\UserRole;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

/**
 * 菜单模块服务层
 *
 * Class MenuService
 * @package App\Services
 */
class MenuService
{

    /**
     * 获取上一级选择菜单树
     * @param int $id // 当前菜单id
     * @return array
     */
    public static function getParentTree($id = 0)
    {
        $filter = Menu::select('id', 'parent_id', 'name', 'type')->orderBy('sort', 'asc')->orderBy('id', 'desc')->get();
        $selected_parent = ['id' => 0, 'name' => ''];
        $collectionKeyBy = collect($filter)->keyBy('id')->all();
        $pid = ($id > 0 && !empty($collectionKeyBy) && isset($collectionKeyBy[$id])) ? $collectionKeyBy[$id]['parent_id'] : 0;
        $collection = collect($filter)->map(function ($item) use ($id, $pid, &$selected_parent) {
            $disabled = $id > 0 && $id == $item->id || in_array($item->type, [2, 3]);
            if ($item->id == $pid) {
                $selected_parent = ['id' => $item->id, 'label' => $item->name];
            }
            return ['id' => $item->id, 'parent_id' => $item->parent_id, 'name' => $item->name, 'disabled' => $disabled];
        });
        $parent_ids = [];
        if (!empty($collectionKeyBy)) {
            while ($pid > 0) {
                foreach ($collectionKeyBy as $id => $value) {
                    if ($pid == $id) {
                        array_unshift($parent_ids, $id);
                        $pid = $value['parent_id'];
                        if ($pid == 0) {
                            break;
                        }
                    }
                }
            }
        }
        $result = TreeService::make($collection);
        return ['items' => $result, 'parent' => $selected_parent, 'parent_ids' => $parent_ids];
    }

    /**
     * 更新或创建菜单信息，同时更新权限表信息
     *
     * @param $menu // 菜单对象，创建场景时，设置为null
     * @param array $data
     * @return bool
     */
    public static function updateOrCreate($menu = null, $data = [])
    {
        if (empty($data)) return false;
        $permission_ids = $data['permission_ids'];
        unset($data['permission_ids']);
        if ($menu == null) {
            $menu = new Menu($data);
            $menu->save();
        } else if ($menu instanceof Menu) {
            $menu->update($data);
        } else {
            return false;
        }

        /**
         * 栏目权限处理
         */

        // $permission_ids当前库对比当前提交，一致则不更新，不同的则删除
        $current_permission_ids = $menu->menuPermission()->pluck('permission_id');
        $deleting_diff_permission_ids = collect($current_permission_ids)->diff($permission_ids)->all();
        $inserting_diff_permission_ids = collect($permission_ids)->diff($current_permission_ids)->all();
        if (!empty($deleting_diff_permission_ids)) {
            MenuPermission::where('menu_id', '=', $menu->id)->whereIn('permission_id', $deleting_diff_permission_ids)->delete();
        }

        // permission_ids当前提交对比当前库，一致则不更新，不同的则写入
        if (!empty($inserting_diff_permission_ids)) {
            $menu_permission_data = collect($inserting_diff_permission_ids)->map(function ($permission_id) use ($menu) {
                return [
                    'menu_id' => $menu->id,
                    'permission_id' => $permission_id,
                    'created_user_id' => $menu->created_user_id,
                    'created_at' => Carbon::now(),
                    'updated_at' => Carbon::now()
                ];
            })->toArray();
            DB::table('menu_permission')->insert($menu_permission_data);
        }
        return true;
    }


    /**
     * 格式化单条菜单
     * @param array $menu
     * @return array
     */
    private static function formatMenuItem($menu = [])
    {
        if (empty($menu)) return [];
        return [
            'name' => $menu['route_name'] ?? '', // 路由名称
            'path' => $menu['route_path'] ?? '',
            'component' => $menu['route_component'] ?? '',
            'alwaysShow' => $menu['route_alwaysShow'] ?? 0,
            'redirect' => $menu['route_redirect'] ?? '',
            'hidden' => !$menu['status'],
            'meta' => [
                'title' => $menu['name'] ?? '',
                'icon' => $menu['route_icon'] ?? '',
                'affix' => $menu['route_affix'] ?? 0,
                'breadcrumb' => $menu['route_breadcrumb'] ?? 1,
                'activeMenu' => $menu['route_activeMenu'] ?? '',
                'isTree' => $menu['route_isTree'] ?? 0,
            ]];
    }

    /**
     * 格式化单条栏目菜单
     * @param array $cate // 栏目
     * @return array
     */
    private static function formatCateMenuItem($cate = [])
    {
        if (empty($cate)) return [];
        // 栏目类型：
        // 频道：目录类型
        //（模型：文章、图集）列表功能：包含菜单类型：列表、添加、修改子菜单
        // 单页功能：菜单类型
        // 链接：菜单类型
        $menu = [];
        switch ($cate['type']) {
            case 1: // 频道
                $menu = [
                    'name' => "InfoCategory{$cate['id']}InfoChannel", // 路由名称
                    'path' => "/info-category/{$cate['id']}/info-channel",
                    'component' => '/empty',
                    'alwaysShow' => true,
                    'redirect' => 'noRedirect',
                    'meta' => [
                        'title' => $cate['name'],
                        'icon' => $cate['icon'],
                        'breadcrumb' => false,
                        'infoCategory' => [
                            'id' => $cate['id']
                        ]
                    ]];
                break;
            case 2: // 列表（文章、图集）
                $info_model_id = $cate['info_model_id'];// 1文章 2图集
                $name = $cate['info_model_id'] == 1 ? "InfoCategory{$cate['id']}InfoNews" : "InfoCategory{$cate['id']}InfoPicture";
                $path = $cate['info_model_id'] == 1 ? "/info-category/{$cate['id']}/info-news" : "/info-category/{$cate['id']}/info-picture";
                $component = $cate['info_model_id'] == 1 ? "/info-news" : "/info-picture";
                $title = $cate['info_model_id'] == 1 ? __('common.article') : __('common.picture');
                $menu = [
                    'name' => $name, // 路由名称
                    'path' => $path,
                    'component' => '/empty',
                    'redirect' => $path . '/index',
                    'alwaysShow' => false,
                    'meta' => [
                        'title' => $cate['name'],
                        'icon' => $cate['icon'],
                    ],
                    'children' => [
                        [ // 列表
                            'name' => $name . 'Index', // 路由名称
                            'path' => $path . "/index",
                            'component' => $component . "/index",
                            'activeMenu' => $path,
                            'hidden' => true,
                            'meta' => [
                                'title' => $title . __('common.index'),
                                'icon' => $cate['icon'],
                                'activeMenu' => $path,
                                'infoCategory' => [
                                    'id' => $cate['id']
                                ]
                            ]
                        ],
                        [ // 添加
                            'name' => $name . 'Create', // 路由名称
                            'path' => $path . "/create",
                            'component' => $component . "/edit",
                            'hidden' => true,
                            'meta' => [
                                'title' => $title . __('common.store'),
                                'activeMenu' => $path,
                                'infoCategory' => [
                                    'id' => $cate['id']
                                ]
                            ]
                        ],
                        [ // 修改
                            'name' => $name . 'Edit', // 路由名称
                            'path' => $path . "/:id(\\d+)/edit",
                            'component' => $component . "/edit",
                            'hidden' => true,
                            'meta' => [
                                'title' => $title . __('common.update'),
                                'activeMenu' => $path,
                                'infoCategory' => [
                                    'id' => $cate['id']
                                ]
                            ]
                        ],
                    ]
                ];
                break;
            case 3: // 单页
                $menu = [
                    'name' => "InfoCategory{$cate['id']}InfoPageEdit", // 路由名称
                    'path' => "/info-category/{$cate['id']}/info-page/edit",
                    'component' => '/info-page/edit',
                    'meta' => [
                        'title' => $cate['name'],
                        'icon' => $cate['icon'],
                        'infoCategory' => [
                            'id' => $cate['id']
                        ]
                    ]];
                break;
            case 4: // 链接
                $menu = [
                    'name' => "InfoCategory{$cate['id']}Link", // 路由名称
                    'path' => $cate['href'] ?? '',
                    'component' => '/empty',
                    'meta' => [
                        'title' => $cate['name'],
                        'icon' => $cate['icon'],
                        'infoCategory' => [
                            'id' => $cate['id']
                        ]
                    ]];
                break;
        }

        return $menu;
    }

    /**
     * 生成登录管理员栏目菜单树
     * @param array $userCateTree // 管理员拥有的栏目树
     * @param int $sys // 是否系统管理员
     * @param array $limitedUserCateIds // 管理员拥有的栏目ID集
     * @return array
     */
    private static function makeLoginUserCateMenuTree($userCateTree = [], $sys = 0, $limitedUserCateIds = [])
    {
        $result = [];
        $index = 0;
        collect($userCateTree)->each(function ($item) use (&$result, $sys, $limitedUserCateIds, &$index) {
            if ($sys || in_array($item['id'], $limitedUserCateIds)) {
                $result[$index] = self::formatCateMenuItem($item);
                if (isset($item['children']) && !empty($item['children'])) {
                    $result[$index]['children'] = self::makeLoginUserCateMenuTree($item['children'], $sys, $limitedUserCateIds);
                }
                $index++;
            }
        });
        return $result;
    }

    /**
     * 生成登录管理员菜单树
     * @param array $userMenuTree // 管理员拥有的菜单树
     * @param int $sys // 是否系统管理员
     * @param array $limitedUserMenuIds // 管理员拥有的菜单ID集
     * @param array $addUserMenuTree // 管理员拥有的栏目树：追加到菜单集中
     * @return array
     */
    private static function makeLoginUserMenuTree($userMenuTree = [], $sys = 0, $limitedUserMenuIds = [], $addUserMenuTree = [])
    {
        $result = [];
        $index = 0;
        collect($userMenuTree)->each(function ($item) use (&$result, $sys, $limitedUserMenuIds, $addUserMenuTree, &$index) {
            if ($sys || in_array($item['id'], $limitedUserMenuIds)) {
                $result[$index] = self::formatMenuItem($item);
                // 追加栏目
                if ($item['relation_cate'] == 1 && !empty($addUserMenuTree)) {
                    $result[$index]['children'] = $addUserMenuTree;
                } else {
                    if (isset($item['children']) && !empty($item['children'])) {
                        $result[$index]['children'] = self::makeLoginUserMenuTree($item['children'], $sys, $limitedUserMenuIds, $addUserMenuTree);
                    }
                }
                $index++;
            }
        });
        return $result;
    }

    /**
     * 获取登录管理员菜单缓存ID标识
     * @param int $userId 管理员Id
     * @return string
     */
    private static function getLoginUserMenuCacheId($userId = 0)
    {
        $userId = $userId > 0 ? $userId : Auth::id();
        return "loginUser{$userId}MenuCache";
    }

    /**
     * 获取登录管理员菜单
     * @param int $userId
     * @return array
     */
    public static function getLoginUserMenu($userId = 0)
    {
        $user = Auth::user();
        if ($userId > 0) {
            $user = User::where('id', $userId)->first();
            if (!$user) return false;
        } else {
            $userId = $user->id;
        }
        $getLoginUserMenuCacheId = self::getLoginUserMenuCacheId($userId);
        $getLoginUserMenuCache = CacheService::getTagsCache(['loginUser', 'menu'], $getLoginUserMenuCacheId);
        if ($getLoginUserMenuCache == null) {
            $sys = $user->sys;
            $limitedUserMenuIds = [];
            $limitedUserCateIds = [];
            if (!$sys) {
                collect($user->userRole)->each(function ($item) use (&$limitedUserMenuIds, &$limitedUserCateIds) {
                    $menuIds = collect($item->roleMenuPermission)->pluck('menu_id')->toArray();
                    $limitedUserMenuIds = array_merge($limitedUserMenuIds, $menuIds);
                    $cateIds = collect($item->roleCategory)->pluck('info_category_id')->toArray();
                    $limitedUserCateIds = array_merge($limitedUserCateIds, $cateIds);
                });
                $limitedUserMenuIds = array_unique($limitedUserMenuIds);
                $limitedUserCateIds = array_unique($limitedUserCateIds);
            }
            // 生成栏目菜单数据
            $allCate = InfoCategory::orderBy('sort', 'asc')->orderBy('id', 'desc')->get();
            $userCateTree = TreeService::make($allCate);
            $addUserMenuTree = self::makeLoginUserCateMenuTree($userCateTree, $sys, $limitedUserCateIds);
            // 生成所有菜单数据
            $allMenu = Menu::orderBy('sort', 'asc')->orderBy('id', 'desc')->get();
            $userMenuTree = TreeService::make($allMenu);
            $getLoginUserMenuCache = self::makeLoginUserMenuTree($userMenuTree, $sys, $limitedUserMenuIds, $addUserMenuTree);
            CacheService::setTagsCache(['loginUser', 'menu'], $getLoginUserMenuCacheId, $getLoginUserMenuCache);
        }
        return $getLoginUserMenuCache;
    }

}
